

/* ----------------------- System includes ----------------------------------*/
#include "stdlib.h"
#include "string.h"

/* ----------------------- Platform includes --------------------------------*/

/* ----------------------- Modbus includes ----------------------------------*/
#include "Muti_MB_config.h"

/* ----------------------- Defines ------------------------------------------*/
#define MUTI_MB_PDU_FUNC_READ_ADDR_OFF               ( MUTI_MB_PDU_DATA_OFF + 0)
#define MUTI_MB_PDU_FUNC_READ_REGCNT_OFF             ( MUTI_MB_PDU_DATA_OFF + 2 )
#define MUTI_MB_PDU_FUNC_READ_SIZE                   ( 4 )
#define MUTI_MB_PDU_FUNC_READ_REGCNT_MAX             ( 0x007D )

#define MUTI_MB_PDU_FUNC_WRITE_ADDR_OFF              ( MUTI_MB_PDU_DATA_OFF + 0)
#define MUTI_MB_PDU_FUNC_WRITE_VALUE_OFF             ( MUTI_MB_PDU_DATA_OFF + 2 )
#define MUTI_MB_PDU_FUNC_WRITE_SIZE                  ( 4 )

#define MUTI_MB_PDU_FUNC_WRITE_MUL_ADDR_OFF          ( MUTI_MB_PDU_DATA_OFF + 0 )
#define MUTI_MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF        ( MUTI_MB_PDU_DATA_OFF + 2 )
#define MUTI_MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF       ( MUTI_MB_PDU_DATA_OFF + 4 )
#define MUTI_MB_PDU_FUNC_WRITE_MUL_VALUES_OFF        ( MUTI_MB_PDU_DATA_OFF + 5 )
#define MUTI_MB_PDU_FUNC_WRITE_MUL_SIZE_MIN          ( 5 )
#define MUTI_MB_PDU_FUNC_WRITE_MUL_REGCNT_MAX        ( 0x0078 )

#define MUTI_MB_PDU_FUNC_READWRITE_READ_ADDR_OFF     ( MUTI_MB_PDU_DATA_OFF + 0 )
#define MUTI_MB_PDU_FUNC_READWRITE_READ_REGCNT_OFF   ( MUTI_MB_PDU_DATA_OFF + 2 )
#define MUTI_MB_PDU_FUNC_READWRITE_WRITE_ADDR_OFF    ( MUTI_MB_PDU_DATA_OFF + 4 )
#define MUTI_MB_PDU_FUNC_READWRITE_WRITE_REGCNT_OFF  ( MUTI_MB_PDU_DATA_OFF + 6 )
#define MUTI_MB_PDU_FUNC_READWRITE_BYTECNT_OFF       ( MUTI_MB_PDU_DATA_OFF + 8 )
#define MUTI_MB_PDU_FUNC_READWRITE_WRITE_VALUES_OFF  ( MUTI_MB_PDU_DATA_OFF + 9 )
#define MUTI_MB_PDU_FUNC_READWRITE_SIZE_MIN          ( 9 )

/* ----------------------- Static functions ---------------------------------*/
eMUTI_MB_Exception    __MUTI_MB_Error2Exception( eMUTI_MB_ErrorCode eErrorCode );

/* ----------------------- Start implementation -----------------------------*/

#if MUTI_MB_FUNC_WRITE_HOLDING_ENABLED > 0

eMUTI_MB_Exception
eMUTI_MB_FuncWriteHoldingRegister( MUTI_MB_object_t *object,  uint8_t * pucFrame, USHORT * usLen )
{
    USHORT          usRegAddress;
    eMUTI_MB_Exception    eStatus = MUTI_MB_EX_NONE;
    eMUTI_MB_ErrorCode    eRegStatus;

    if( *usLen == ( MUTI_MB_PDU_FUNC_WRITE_SIZE + MUTI_MB_PDU_SIZE_MIN ) )
    {
        usRegAddress = ( USHORT )( pucFrame[MUTI_MB_PDU_FUNC_WRITE_ADDR_OFF] << 8 );
        usRegAddress |= ( USHORT )( pucFrame[MUTI_MB_PDU_FUNC_WRITE_ADDR_OFF + 1] );
        //usRegAddress++;

        /* Make callback to update the value. */

        if(object->protocol_cb != NULL)
        {
            eRegStatus = object->protocol_cb(object->function_code, &pucFrame[MUTI_MB_PDU_FUNC_WRITE_VALUE_OFF],
                                             usRegAddress, 1, MB_REG_WRITE );
        }

        // eRegStatus = eMBRegHoldingCB( &pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF],
        //                               usRegAddress, 1, MB_REG_WRITE );

        /* If an error occured convert it into a Modbus exception. */
        if( eRegStatus != MUTI_MB_ENOERR )
        {
            eStatus = __MUTI_MB_Error2Exception( eRegStatus );
        }
    }
    else
    {
        /* Can't be a valid request because the length is incorrect. */
        eStatus = MUTI_MB_EX_ILLEGAL_DATA_VALUE;
    }
    return eStatus;
}
#endif

#if MUTI_MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED > 0
eMUTI_MB_Exception
eMUTI_MB_FuncWriteMultipleHoldingRegister(MUTI_MB_object_t *object,  UCHAR * pucFrame, USHORT * usLen )
{
    USHORT          usRegAddress;
    USHORT          usRegCount;
    UCHAR           ucRegByteCount;

    eMUTI_MB_Exception    eStatus = MUTI_MB_EX_NONE;
    eMUTI_MB_ErrorCode    eRegStatus;

    if( *usLen >= ( MUTI_MB_PDU_FUNC_WRITE_MUL_SIZE_MIN + MUTI_MB_PDU_SIZE_MIN ) )
    {
        usRegAddress = ( USHORT )( pucFrame[MUTI_MB_PDU_FUNC_WRITE_MUL_ADDR_OFF] << 8 );
        usRegAddress |= ( USHORT )( pucFrame[MUTI_MB_PDU_FUNC_WRITE_MUL_ADDR_OFF + 1] );
        //usRegAddress++;

        usRegCount = ( USHORT )( pucFrame[MUTI_MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF] << 8 );
        usRegCount |= ( USHORT )( pucFrame[MUTI_MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF + 1] );

        ucRegByteCount = pucFrame[MUTI_MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF];

        if( ( usRegCount >= 1 ) &&
            ( usRegCount <= MUTI_MB_PDU_FUNC_WRITE_MUL_REGCNT_MAX ) &&
            ( ucRegByteCount == ( UCHAR ) ( 2 * usRegCount ) ) )
        {
            /* Make callback to update the register values. */

            if(object->protocol_cb != NULL)
            {
                eRegStatus = object->protocol_cb(object->function_code, &pucFrame[MUTI_MB_PDU_FUNC_WRITE_MUL_VALUES_OFF],
                                                 usRegAddress, usRegCount, MB_REG_WRITE);
            }

            // eRegStatus =
            //     eMBRegHoldingCB( &pucFrame[MB_PDU_FUNC_WRITE_MUL_VALUES_OFF],
            //                      usRegAddress, usRegCount, MB_REG_WRITE );

            /* If an error occured convert it into a Modbus exception. */
            if( eRegStatus != MUTI_MB_ENOERR )
            {
                eStatus = __MUTI_MB_Error2Exception( eRegStatus );
            }
            else
            {
                /* The response contains the function code, the starting
                 * address and the quantity of registers. We reuse the
                 * old values in the buffer because they are still valid.
                 */
                *usLen = MUTI_MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF;
            }
        }
        else
        {
            eStatus = MUTI_MB_EX_ILLEGAL_DATA_VALUE;
        }
    }
    else
    {
        /* Can't be a valid request because the length is incorrect. */
        eStatus = MUTI_MB_EX_ILLEGAL_DATA_VALUE;
    }
    return eStatus;
}
#endif

#if MUTI_MB_FUNC_READ_HOLDING_ENABLED > 0

eMUTI_MB_Exception
eMUTI_MB_FuncReadHoldingRegister( MUTI_MB_object_t *object, UCHAR * pucFrame, USHORT * usLen )
{
    USHORT          usRegAddress;
    USHORT          usRegCount;
    UCHAR          *pucFrameCur;

    eMUTI_MB_Exception    eStatus = MUTI_MB_EX_NONE;
    eMUTI_MB_ErrorCode    eRegStatus;

    if( *usLen == ( MUTI_MB_PDU_FUNC_READ_SIZE + MUTI_MB_PDU_SIZE_MIN ) )
    {
        usRegAddress = ( USHORT )( pucFrame[MUTI_MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
        usRegAddress |= ( USHORT )( pucFrame[MUTI_MB_PDU_FUNC_READ_ADDR_OFF + 1] );
        //usRegAddress++;

        usRegCount = ( USHORT )( pucFrame[MUTI_MB_PDU_FUNC_READ_REGCNT_OFF] << 8 );
        usRegCount = ( USHORT )( pucFrame[MUTI_MB_PDU_FUNC_READ_REGCNT_OFF + 1] );

        /* Check if the number of registers to read is valid. If not
         * return Modbus illegal data value exception. 
         */
        if( ( usRegCount >= 1 ) && ( usRegCount <= MUTI_MB_PDU_FUNC_READ_REGCNT_MAX ) )
        {
            /* Set the current PDU data pointer to the beginning. */
            pucFrameCur = &pucFrame[MUTI_MB_PDU_FUNC_OFF];
            *usLen = MUTI_MB_PDU_FUNC_OFF;

            /* First byte contains the function code. */
            *pucFrameCur++ = MUTI_MB_FUNC_READ_HOLDING_REGISTER;
            *usLen += 1;

            /* Second byte in the response contain the number of bytes. */
            *pucFrameCur++ = ( UCHAR ) ( usRegCount * 2 );
            *usLen += 1;

            /* Make callback to fill the buffer. */

            if(object->protocol_cb != NULL)
            {
                eRegStatus = object->protocol_cb(object->function_code, pucFrameCur, usRegAddress, usRegCount, MB_REG_READ);
            }

            //eRegStatus = eMBRegHoldingCB( pucFrameCur, usRegAddress, usRegCount, MB_REG_READ );


            /* If an error occured convert it into a Modbus exception. */
            if( eRegStatus != MUTI_MB_ENOERR )
            {
                eStatus = __MUTI_MB_Error2Exception( eRegStatus );
            }
            else
            {
                *usLen += usRegCount * 2;
            }
        }
        else
        {
            eStatus = MUTI_MB_EX_ILLEGAL_DATA_VALUE;
        }
    }
    else
    {
        /* Can't be a valid request because the length is incorrect. */
        eStatus = MUTI_MB_EX_ILLEGAL_DATA_VALUE;
    }
    return eStatus;
}

#endif

#if MUTI_MB_FUNC_READWRITE_HOLDING_ENABLED > 0

eMUTI_MB_Exception
eMUTI_MB_FuncReadWriteMultipleHoldingRegister(MUTI_MB_object_t *object,  UCHAR * pucFrame, USHORT * usLen )
{
    USHORT          usRegReadAddress;
    USHORT          usRegReadCount;
    USHORT          usRegWriteAddress;
    USHORT          usRegWriteCount;
    UCHAR           ucRegWriteByteCount;
    UCHAR          *pucFrameCur;

    eMUTI_MB_Exception    eStatus = MUTI_MB_EX_NONE;
    eMUTI_MB_ErrorCode    eRegStatus;

    if( *usLen >= ( MUTI_MB_PDU_FUNC_READWRITE_SIZE_MIN + MUTI_MB_PDU_SIZE_MIN ) )
    {
        usRegReadAddress = ( USHORT )( pucFrame[MUTI_MB_PDU_FUNC_READWRITE_READ_ADDR_OFF] << 8U );
        usRegReadAddress |= ( USHORT )( pucFrame[MUTI_MB_PDU_FUNC_READWRITE_READ_ADDR_OFF + 1] );
        //usRegReadAddress++;

        usRegReadCount = ( USHORT )( pucFrame[MUTI_MB_PDU_FUNC_READWRITE_READ_REGCNT_OFF] << 8U );
        usRegReadCount |= ( USHORT )( pucFrame[MUTI_MB_PDU_FUNC_READWRITE_READ_REGCNT_OFF + 1] );

        usRegWriteAddress = ( USHORT )( pucFrame[MUTI_MB_PDU_FUNC_READWRITE_WRITE_ADDR_OFF] << 8U );
        usRegWriteAddress |= ( USHORT )( pucFrame[MUTI_MB_PDU_FUNC_READWRITE_WRITE_ADDR_OFF + 1] );
        //usRegWriteAddress++;

        usRegWriteCount = ( USHORT )( pucFrame[MUTI_MB_PDU_FUNC_READWRITE_WRITE_REGCNT_OFF] << 8U );
        usRegWriteCount |= ( USHORT )( pucFrame[MUTI_MB_PDU_FUNC_READWRITE_WRITE_REGCNT_OFF + 1] );

        ucRegWriteByteCount = pucFrame[MUTI_MB_PDU_FUNC_READWRITE_BYTECNT_OFF];

        if( ( usRegReadCount >= 1 ) && ( usRegReadCount <= 0x7D ) &&
            ( usRegWriteCount >= 1 ) && ( usRegWriteCount <= 0x79 ) &&
            ( ( 2 * usRegWriteCount ) == ucRegWriteByteCount ) )
        {
            /* Make callback to update the register values. */

             if(object->protocol_cb != NULL)
            {
                eRegStatus = object->protocol_cb(object->function_code, &pucFrame[MUTI_MB_PDU_FUNC_READWRITE_WRITE_VALUES_OFF],
                                                usRegWriteAddress, usRegWriteCount, MB_REG_WRITE);
            }

            // eRegStatus = eMBRegHoldingCB( &pucFrame[MB_PDU_FUNC_READWRITE_WRITE_VALUES_OFF],
            //                               usRegWriteAddress, usRegWriteCount, MB_REG_WRITE );

            if( eRegStatus == MUTI_MB_ENOERR )
            {
                /* Set the current PDU data pointer to the beginning. */
                pucFrameCur = &pucFrame[MUTI_MB_PDU_FUNC_OFF];
                *usLen = MUTI_MB_PDU_FUNC_OFF;

                /* First byte contains the function code. */
                *pucFrameCur++ = MUTI_MB_FUNC_READWRITE_MULTIPLE_REGISTERS;
                *usLen += 1;

                /* Second byte in the response contain the number of bytes. */
                *pucFrameCur++ = ( UCHAR ) ( usRegReadCount * 2 );
                *usLen += 1;

                /* Make the read callback. */

                if(object->protocol_cb != NULL)
                {
                    eRegStatus = object->protocol_cb(object->function_code, pucFrameCur, usRegReadAddress, usRegReadCount, MB_REG_READ);
                }
                // eRegStatus =
                //     eMBRegHoldingCB( pucFrameCur, usRegReadAddress, usRegReadCount, MB_REG_READ );



                if( eRegStatus == MUTI_MB_ENOERR )
                {
                    *usLen += 2 * usRegReadCount;
                }
            }
            if( eRegStatus != MUTI_MB_ENOERR )
            {
                eStatus = __MUTI_MB_Error2Exception( eRegStatus );
            }
        }
        else
        {
            eStatus = MUTI_MB_EX_ILLEGAL_DATA_VALUE;
        }
    }
    return eStatus;
}

#endif
